package test;

import static org.junit.Assert.*;

import hospital.Hospital;

import java.util.ArrayList;

import main.*;
import movement.Location;

import org.junit.*;

import unit.*;

import dispatch.DispatchCenter;
import emergency.*;

public class useCaseTestDispatchUnitsToDisaster {

	FacadeTime ft;
	FacadeUnit fu;
	FacadeDispatcher fd;
	World world; 
	DispatchCenter dispatchcenter;
	Garage garage;
	Disaster disaster;
	ArrayList<Emergency> emergencies;
	Emergency fire,robbery,trafficaccident;
	Unit p1,p2,p3,p4,p5;
	Unit a1,a2,a3,a4,a5;
	Unit f1,f2,f3,f4,f5;
	Hospital hospital;
	
	@Before
	public void setUp() throws Exception {
		dispatchcenter = new DispatchCenter("DC", new Location(0,0,"DCC"),new Location(5,0,"G"));
		garage = dispatchcenter.getGarage();
		
		world = new World(null);
		world.setDispatchCenter(dispatchcenter);
		
		ft = new FacadeTime(world);
		fu = new FacadeUnit(world);
		fd = new FacadeDispatcher(world);
		
		p1 = new PoliceCar("P1", 100, garage);
		p2 = new PoliceCar("P2", 110, garage);
		p3 = new PoliceCar("P3", 120, garage);
		p4 = new PoliceCar("P4", 130, garage);
		p5 = new PoliceCar("P5", 140, garage);
		
		a1 = new Ambulance("A1", 100, garage);
		a2 = new Ambulance("A2", 125, garage);
		a3 = new Ambulance("A3", 120, garage);
		a4 = new Ambulance("A4", 130, garage);
		a5 = new Ambulance("A5", 110, garage);
		
		f1 = new FireTruck("F1", 90, garage, Fire.Size.HOUSE);
		f2 = new FireTruck("F2", 120, garage, Fire.Size.HOUSE);
		f3 = new FireTruck("F3", 190, garage, Fire.Size.HOUSE);
		f4 = new FireTruck("F4", 150, garage, Fire.Size.LOCAL);
		f5 = new FireTruck("F5", 80, garage, Fire.Size.HOUSE);
		
		fire = new Fire(new Location(12,12,"l"), Severity.NORMAL, dispatchcenter, Fire.Size.HOUSE, false, 1, 1);
		robbery = new Robbery(new Location(50,50,"R"), Severity.SERIOUS, dispatchcenter, true, true);
		trafficaccident = new TrafficAccident(new Location(75,75,"T"), Severity.NORMAL, dispatchcenter, 1, 1);

		emergencies = new ArrayList<Emergency>();
		emergencies.add(fire);
		emergencies.add(robbery);
		emergencies.add(trafficaccident);
		
		disaster = new Disaster(dispatchcenter, emergencies, "Testje");
		
		hospital = new Hospital("Hospital",new Location(45,45,"L"));
	}
	
	@Test
	public void testDispatchUnits() throws Exception{
		assertFalse(p1.isAssigned());
		assertFalse(p2.isAssigned());
		assertFalse(p3.isAssigned());
		assertFalse(p4.isAssigned());
		assertFalse(p5.isAssigned());
		assertFalse(a1.isAssigned());
		assertFalse(a3.isAssigned());
		assertFalse(a4.isAssigned());
		assertFalse(a5.isAssigned());
		assertFalse(f1.isAssigned());
		assertFalse(f2.isAssigned());
		assertFalse(f3.isAssigned());
		assertFalse(f4.isAssigned());
		assertFalse(f5.isAssigned());
		
		fd.assignAllUnits(disaster);

		//3 units are assigned to the serious Robbery!
		assertTrue(p1.isAssigned());
		assertTrue(p2.isAssigned());
		assertTrue(p3.isAssigned());
		
		//3 policecars move to SERIOUS robbery ( = ADVANCE TIME ) 
		ft.simulatedTimeBy(2000);

		//all policecars do their task
		fu.finishEmergency(p1);
		fu.finishEmergency(p2);
		fu.finishEmergency(p3);
		assertEquals(fire, p1.getEmergency()); // p1 is assigned to the fire 
		assertEquals(disaster, p2.getEmergency()); //p2 has no new job => stays on disaster
		assertEquals(disaster, p3.getEmergency()); //p3 has no new job => stays on disaster
		assertEquals(fire,f1.getEmergency()); // f1 is assigned to the fire 
		assertEquals(fire,f2.getEmergency()); // f2 is assigned to the fire 
		assertEquals(fire,a1.getEmergency()); // a1 is assigned to the fire 
		assertEquals(fire,a2.getEmergency()); // a2 is assigned to the fire 
		
		//units move to fire
		ft.simulatedTimeBy(2000);
		
		fu.finishEmergency(p1);
		fu.finishEmergency(f1);
		fu.finishEmergency(f2);
		
		fu.assignHospital(a1, hospital);
		fu.assignHospital(a2, hospital);
		
		ft.simulatedTimeBy(2000); //ambulance moves to hospital
		
		fu.finishEmergency(a1);
		fu.finishEmergency(a2);
		
		assertEquals(disaster,p1.getEmergency()); 
		assertEquals(trafficaccident,p2.getEmergency());
		assertEquals(trafficaccident,f1.getEmergency());
		assertEquals(disaster,f2.getEmergency());
		assertEquals(trafficaccident,a1.getEmergency());
		assertEquals(disaster,a2.getEmergency());
		
		ft.simulatedTimeBy(2000); // go to trafficaccident
		
		fu.finishEmergency(p2); // p2 it's task is done 
		fu.finishEmergency(f1); // f1 it's task is done 
		
		fu.assignHospital(a1, hospital); // picking hospital for the ambulance
		
		ft.simulatedTimeBy(2000);
		
		fu.finishEmergency(a1);

		assertEquals(0,disaster.getUnits().size());
		assertEquals(0,robbery.getUnits().size());
		assertEquals(0,fire.getUnits().size());
		assertEquals(0,trafficaccident.getUnits().size());
		
		assertEquals("statecompleted",robbery.getStateName());
		assertEquals("statecompleted",fire.getStateName());
		assertEquals("statecompleted",trafficaccident.getStateName());
		assertEquals("statecompleted",disaster.getStateName());
		
		assertFalse(p1.isAssigned());
		assertFalse(p2.isAssigned());
		assertFalse(p3.isAssigned());
		assertFalse(p4.isAssigned());
		assertFalse(p5.isAssigned());
		assertFalse(a1.isAssigned());
		assertFalse(a3.isAssigned());
		assertFalse(a4.isAssigned());
		assertFalse(a5.isAssigned());
		assertFalse(f1.isAssigned());
		assertFalse(f2.isAssigned());
		assertFalse(f3.isAssigned());
		assertFalse(f4.isAssigned());
		assertFalse(f5.isAssigned());
	}
	
	@Test
	public void testDispatchUnitsRevokeUnit() throws Exception{
		assertFalse(p1.isAssigned());
		assertFalse(p2.isAssigned());
		assertFalse(p3.isAssigned());
		assertFalse(p4.isAssigned());
		assertFalse(p5.isAssigned());
		assertFalse(a1.isAssigned());
		assertFalse(a3.isAssigned());
		assertFalse(a4.isAssigned());
		assertFalse(a5.isAssigned());
		assertFalse(f1.isAssigned());
		assertFalse(f2.isAssigned());
		assertFalse(f3.isAssigned());
		assertFalse(f4.isAssigned());
		assertFalse(f5.isAssigned());
		
		fd.assignAllUnits(disaster);
		
		ft.simulatedTimeBy(10);
		
		assertEquals(robbery, p1.getEmergency());
		
		fd.revokeUnit(p1);
		
		assertEquals(robbery, p1.getEmergency());
		
		ft.simulatedTimeBy(10000);	
		fu.finishEmergency(p1);
		fu.finishEmergency(p2);
		fu.finishEmergency(p3);
		
		assertEquals(null, p1.getEmergency());
		
	}
	
	@Test
	public void testDispatchUnitsUnitBreaksDown() throws Exception{
		assertFalse(p1.isAssigned());
		assertFalse(p2.isAssigned());
		assertFalse(p3.isAssigned());
		assertFalse(p4.isAssigned());
		assertFalse(p5.isAssigned());
		assertFalse(a1.isAssigned());
		assertFalse(a3.isAssigned());
		assertFalse(a4.isAssigned());
		assertFalse(a5.isAssigned());
		assertFalse(f1.isAssigned());
		assertFalse(f2.isAssigned());
		assertFalse(f3.isAssigned());
		assertFalse(f4.isAssigned());
		assertFalse(f5.isAssigned());
		assertFalse(p1.isBroken());
		assertFalse(p2.isBroken());
		assertFalse(p3.isBroken());
		assertFalse(p4.isBroken());
		assertFalse(p5.isBroken());
		assertFalse(a1.isBroken());
		assertFalse(a3.isBroken());
		assertFalse(a4.isBroken());
		assertFalse(a5.isBroken());
		assertFalse(f1.isBroken());
		assertFalse(f2.isBroken());
		assertFalse(f3.isBroken());
		assertFalse(f4.isBroken());
		assertFalse(f5.isBroken());
		
		p1.brokeDown();
		
		fd.assignAllUnits(disaster);
		
		//3 units are assigned to the serious Robbery! , 1 unit is broken
		assertFalse(p1.isAssigned());
		assertTrue(p2.isAssigned());
		assertTrue(p3.isAssigned());
		assertTrue(p4.isAssigned());
		
		//3 policecars travelling to SERIOUS robbery ( = ADVANCE TIME ) 
		ft.simulatedTimeBy(10);
		
		assertTrue(robbery.getUnits().contains(p2));
		fu.breakDown(p2);

		assertTrue(p2.isBroken());
		assertEquals(robbery.getStateName(),"stateinprogress");
		assertEquals(robbery.getDisaster(),disaster);
		assertFalse(robbery.getUnits().contains(p2));
		assertTrue(disaster.getUnits().contains(p2));
		assertEquals(disaster, p2.getEmergency());
		
		fd.assignUnit(disaster, p5); // assigning replacement(p4) for p2 

		assertTrue(robbery.getUnits().contains(p5));
		assertEquals(robbery.getStateName(),"stateinprogress");
		assertEquals(robbery, p5.getEmergency());
		assertEquals(disaster, p5.getEmergency().getDisaster());
		
		ft.simulatedTimeBy(10);
		
		fu.repair(p1);
		
		ft.simulatedTimeBy(10);
		
		fu.breakDown(p5);
		
		assertTrue(p5.isBroken());
		assertEquals(robbery.getStateName(),"stateinprogress"); // new unit -> stays in progress
		assertEquals(robbery.getDisaster(),disaster);
		assertFalse(robbery.getUnits().contains(p5));
		assertTrue(disaster.getUnits().contains(p5));
		assertEquals(disaster, p5.getEmergency());
		
		fd.assignUnit(disaster, p1); // assigning replacement(p1) for p5 

		ft.simulatedTimeBy(10);
		assertTrue(robbery.getUnits().contains(p1));
		assertEquals(robbery.getStateName(),"stateinprogress");
		assertEquals(robbery, p1.getEmergency());
		assertEquals(disaster, p1.getEmergency().getDisaster());
		
		ft.simulatedTimeBy(1000);
		//all policecars do their task
		
		fu.finishEmergency(p3);
		fu.finishEmergency(p4);
		fu.finishEmergency(p1);
		
		assertEquals(robbery.getStateName(),"statecompleted");

		assertEquals(disaster, p1.getEmergency());
		assertEquals(disaster, p2.getEmergency());

		//p3 first ready => assigned to next emergency ( FIRE )
		assertEquals(fire, p3.getEmergency());
		
		assertEquals(disaster, p4.getEmergency());
		assertEquals(disaster, p5.getEmergency());
		
		// f1 and f2 are assigned to next emergency ( FIRE ) 
		assertEquals(fire, f1.getEmergency());
		assertEquals(fire, f2.getEmergency());
		
		//next 3 aren't needed for this disaster
		assertEquals(null, f3.getEmergency());
		assertEquals(null, f4.getEmergency());
		assertEquals(null, f5.getEmergency());
		assertEquals(fire, a1.getEmergency());
		assertEquals(fire, a2.getEmergency());
		assertEquals(null, a3.getEmergency());
		assertEquals(null, a4.getEmergency());
		assertEquals(null, a5.getEmergency());

		ft.simulatedTimeBy(1);
		fu.breakDown(f2);
		ft.simulatedTimeBy(1);
		
		assertTrue(f2.isBroken());
		assertEquals(fire.getStateName(),"stateinprogress");
		assertEquals(fire.getDisaster(),disaster);
		assertFalse(fire.getUnits().contains(f2));
		assertTrue(disaster.getUnits().contains(f2));
		assertEquals(disaster, f2.getEmergency());
		
		fd.assignUnit(disaster, f3); // assigning replacement(f3) for f2
		ft.simulatedTimeBy(10);
		
		assertTrue(fire.getUnits().contains(f3));
		assertEquals(fire.getStateName(),"stateinprogress");
		assertEquals(fire, f3.getEmergency());
		assertEquals(disaster, f3.getEmergency().getDisaster());
		
		ft.simulatedTimeBy(1000);
		//all units do their task
		fu.finishEmergency(f3);
		fu.finishEmergency(f1);
		fu.finishEmergency(p3);
		
		Hospital h = new Hospital("Hospital", new Location(10,10,"Al"));
		fu.assignHospital(a1, h);
		fu.assignHospital(a2, h);
		
		ft.simulatedTimeBy(1000);
		
		fu.finishEmergency(a1);
		fu.finishEmergency(a2);
		
		assertEquals(fire.getStateName(),"statecompleted");
		
		ft.simulatedTimeBy(1000);
		
		fu.finishEmergency(p4);
		fu.finishEmergency(f3);
		
		fu.assignHospital(a1, h);
		
		ft.simulatedTimeBy(1000);
		
		assertEquals(trafficaccident.getStateName(),"stateinprogress");
		
		fu.finishEmergency(a1);
		
		assertEquals(trafficaccident.getStateName(),"statecompleted");
		
		assertFalse(p1.isAssigned());
		assertFalse(p2.isAssigned());
		assertFalse(p3.isAssigned());
		assertFalse(p4.isAssigned());
		assertFalse(p5.isAssigned());
		assertFalse(a1.isAssigned());
		assertFalse(a3.isAssigned());
		assertFalse(a4.isAssigned());
		assertFalse(a5.isAssigned());
		assertFalse(f1.isAssigned());
		assertFalse(f2.isAssigned());
		assertFalse(f3.isAssigned());
		assertFalse(f4.isAssigned());
		assertFalse(f5.isAssigned());
		
	}
}
